/*******************************************************************************
 * Copyright (c) 2009 IBM Corporation and others
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.aseclipse.osgi.loader
{
    import flash.display.Loader;
    import flash.events.Event;
    import flash.events.IOErrorEvent;
    import flash.events.ProgressEvent;
    import flash.net.URLRequest;
    import flash.system.ApplicationDomain;
    import flash.system.LoaderContext;
    
    import mx.core.Application;
    import mx.logging.ILogger;
    import mx.logging.Log;
    
    /*****
    * A global loader to load swc libraries from server or external websites.
    * 1) If swc file is from UI server, we use *.swc as method input, actually we load *\library.swf file;
    * 2) if swc file is from external websites, please directly use swf url;
    * Usage:
    *    BundleLibraryLoader.getInstance().load("core.swc", callback, null);
    * 
    */ 
    public class BundleLibraryLoader
    {
        private static var globalLoader:BundleLibraryLoader;
        private var loaderContext:LoaderContext = null;
        private static var log_:ILogger = Log.getLogger("BundleLibraryLoader");
        private static var libraryIndex:Object = new Object();
        private var currentLib:String = null;
        // Don't invoke "new OSGiLibraryLoader()" in clients
        public function BundleLibraryLoader()
        {
            if(globalLoader != null) {
                throw new Error("BundleLibraryLoader is a singleton instance, can't initialize " + 
                        "two instances. Please use BundleLibraryLoader.getInstance()");
            }
            loaderContext = new LoaderContext();
            loaderContext.applicationDomain = ApplicationDomain.currentDomain;            
        }

        public static function getInstance():BundleLibraryLoader {
            if(globalLoader == null) {
                globalLoader = new BundleLibraryLoader();
            }
            return globalLoader;
        }
        
        /***
        * @param swcfiles can be "core.swc;core2.swc" or "http://base.google.com/maps/map.swf"
        * @param success can be a function or function array, as callback after finishing loading libraries. 
        *    callback function is a function without input/output.
        */ 
        public function load(swcfiles:String, success:*, fail:* = null):void {
            log_.debug("[load] request: " + swcfiles);
            var array:Array = swcfiles.split(";");
            var functio:Function = function():void {
               if(success != null) {
                   if(success is Function) {
                       (success as Function).apply(this, null);
                   } else if(success is Array) {
                       var funcs:Array = success as Array;
                       for(var i:int = 0; i< funcs.length; i++ ) {
                           try {
                              var func:Function = funcs[i] as Function;
                              func.apply(this, null);
                           } catch(err:Error) {
                              log_.error("[BundleLibraryLoader] fail to invoke callback, maybe UI logic won't work");  
                           }
                       }
                   }
                   success = null
               }
            }; 
            loadSWC(array, functio, function():void {
               log_.error("[BundleLibraryLoader] fail to load partial swc files, maybe UI logic won't work");
               functio.apply(this, null);
            });
        }
        
        protected function loadSWC(swcfiles:Array, success:Function, fail:Function):void {
            if(swcfiles == null || swcfiles.length == 0) {
                success.apply(this, null);
                return;
            }
            var type:String = swcfiles.shift() as String;
            currentLib = type;
            var moduleName:String = analyze(type);
            log_.info("[BundleLibraryLoader] --> load library '"+moduleName+"' start.");
            // check whether already loaded or not
            if(libraryIndex[moduleName] != null) {
                log_.info("[BundleLibraryLoader] --> library '"+moduleName+"' is already loaded.");
                loadSWC(swcfiles, success, fail);
                return;
            }
            // start to load swf file
            var loader:Loader = new Loader();
            var request:URLRequest = new URLRequest(moduleName);
            var f1:Function = function(event:Event):void {
                log_.info("[BundleLibraryLoader] --> load library '"+moduleName+"' successfully.");
                //Should recorde the loader to make the loader not to be GCed, flex bug http://bugs.adobe.com/jira/browse/FB-13014
                libraryIndex[moduleName] = loader;
                loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, f1);
                loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, f2);
                loader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, progressHander);
                loadSWC(swcfiles, success, fail);
            };
            var f2:Function = function(event2:IOErrorEvent):void {
                log_.info("[BundleLibraryLoader] --> fail to load library '"+moduleName+"' because of " + event2.toString());
                loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, f1);
                loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, f2);
                loader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS, progressHander);
                loadSWC(swcfiles, fail, fail);
            }
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, f1);
            loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, f2);
            loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressHander);    
            loader.load(request, loaderContext);
        }
        
        private function progressHander(event:ProgressEvent):void {
        }
                
        private function analyze(type:String):String {
            var moduleName:String = type;
            if(moduleName.indexOf("http://") != 0 && moduleName.indexOf("https://") != 0) {
            	moduleName = BundleConstants.getURLPrefix() + moduleName;
            }
            if(moduleName.lastIndexOf(".swc") == moduleName.length - 4) {
                moduleName = moduleName.substring(0, moduleName.length - 4) + "/library.swf";
            } else if(moduleName.lastIndexOf(".swf") == moduleName.length - 4) {
            	//load swf
            } else {
                // it is library name without subfix ".swc"/".swf"
	            // load debug version, if the library support debug
	            var devDebug:Boolean = false;
	            if(null!=Application.application.parameters.dev_debug) {
		            devDebug = true;
		        }
		        if(devDebug) {
	            	moduleName = moduleName + "/library_debug.swf";
	            } else {
                    moduleName = moduleName + "/library.swf";
                }
            }
            moduleName = BundleConstants.updateSubfix(moduleName);
            
            return moduleName;
        }
        
    }
}